#include <stdlib.h>
#include <stdio.h>
#include <nds.h>
#include <string.h>
#include <ctype.h>

// common headers
#include "common.h"

// local headers
#include "extensionlist.h"

#include "improvedextensionlist.h"

sIEL *IEL_add(sIEL **el, char *ext, size_t extl) {
	sIEL *tmp=NULL;

	if(*el) {
		sIEL *_el=*el;

		while(_el->prev && _el->prev->extl >= extl) _el=_el->prev;
		while(_el && _el->extl < extl) {
			if(!_el->next) break;
			_el=_el->next;
		}

		tmp=IEL_search(_el, ext, extl);
		if(tmp) return tmp;

		tmp=_el->next;

		_el->next=(sIEL *)xcalloc(1, sizeof(sIEL));

		if(tmp) tmp->prev=_el->next;
		_el->next->prev=_el;
		_el->next->next=tmp;

		tmp=_el->next;
	}
	else {
		tmp=*el=(sIEL *)xcalloc(1, sizeof(sIEL));
	}

	tmp->ext=ext;
	tmp->extl=extl;
	tmp->hash=IEL_hash(ext, extl);

	return tmp;
}

int IEL_add_EL(sIEL **iel, sEL el, sPlugin *plug) {
    if(!iel) return 1;

    int i;
    sIEL *tmp;
    for(i=0; i<el.extnum && el.exts[i]; i++) {
        tmp=IEL_add(iel, el.exts[i], strlen(el.exts[i]));
        tmp->plug=plug;
    }

    return 0;
}

int IEL_add_copy_EL(sIEL **iel, sEL el, sPlugin *plug) {
    if(!iel) return 1;

    int i;
    sIEL *tmp;
    for(i=0; i<el.extnum && el.exts[i]; i++) {
        size_t len=strlen(el.exts[i]);
        tmp=IEL_add(iel, xmemdup(el.exts[i], len), len);
        tmp->plug=plug;
    }

    return 0;
}

u32 IEL_hash(char *str, size_t len) {
	u32 hash=0;

	while(len--) {
		hash+=(u32)tolower(*str++);
		hash+=hash<<10;
		hash^=hash>>6;
	}

	hash+=hash<<3;
	hash^=hash>>11;
	hash+=hash<<15;

	return hash;
}

sIEL *IEL_search(sIEL *el, char *ext, size_t extl) {
	while(el->prev && el->prev->extl >= extl) el=el->prev;
	while(el && el->extl!=extl) el=el->next;

	if(!el) return NULL;

	u32 hash=IEL_hash(ext, extl);

	while(el && el->extl==extl) {
		if(el->hash==hash && !strncasecmp(el->ext, ext, extl)) return el;

		el=el->next;
	}

	return NULL;
}

